using Godot;
using System;
using Godot.Collections;

public partial class SceneSwitch : Node
{
    [Signal]
    public delegate void SceneStartEventHandler();

    [Export]
    public Dictionary<string, string> Scene { get; set; } = [];
    [Export]
    public string InitialScene { get; set; } = "";
    [Export]
    public string CurrentSceneName { get; private set; } = "";

    private System.Collections.Generic.Dictionary<string, PackedScene> _cachedScene = [];
    private Node _currentScene;
    private Timer _intervaTimer;
    private float _arrangeTime = -2.0f;
    private bool _arrangingScene = true;

    // Node references
    private CinematicCamera _camera;
    private Player _player;

    public override void _Ready()
    {
        _intervaTimer = GetNode<Timer>("IntervalTimer");
        var map = GetNode<NodeReferenceMap>(Constants.NodeRefMapPath);
        _camera = map.GameCamera;
        _player = map.MainPlayer;

        var useKey = InitialScene;
        if (useKey == "")
        {
            var iter = Scene.Keys.GetEnumerator();
            if (iter.MoveNext())
                useKey = iter.Current;
        }
        if (useKey != "")
        {
            CurrentSceneName = useKey;
            CallDeferred(MethodName.ArrangeStartScene, 0.0f);
            CallDeferred(MethodName.SwitchToScene, useKey);
        }
    }

    // Export interfaces
    public void SwitchToScene(string sceneName)
    {
        if (_cachedScene.TryGetValue(sceneName, out PackedScene scene))
        {
            // target scene is cached
            CurrentSceneName = sceneName;
            InstanciateSceneNode(scene);
        }
        else
        {
            // load target scene
            if (Scene.TryGetValue(sceneName, out string srcPath))
            {
                PackedScene loadScene = ResourceLoader.Load<PackedScene>(srcPath);
                _cachedScene.Add(sceneName, loadScene);
                CurrentSceneName = sceneName;
                InstanciateSceneNode(loadScene);
            }
            else
            {
                GD.PrintErr($"Scene not found: {sceneName}.");
            }
        }
    }

    public void ArrangeStartScene(float interval)
    {
        _arrangeTime = interval;
        _arrangingScene = true;
    }

    private void InstanciateSceneNode(PackedScene scene)
    {
        _player.SkipInputCheck();
        if (_currentScene != null)
        {
            RemoveChild(_currentScene);
            _currentScene.QueueFree();
        }
        _currentScene = scene.Instantiate();
        AddChild(_currentScene);

        if (_arrangeTime > -1.0f)
        {
            if (_arrangeTime <= 0.0f)
            {
                Signal_IntervalTimerTimeout();
            }
            else
            {
                _intervaTimer.WaitTime = _arrangeTime;
                _intervaTimer.Start();
            }
            _arrangeTime = -2.0f;
        }
    }

    // GODOT - Signals
    private void Signal_IntervalTimerTimeout()
    {
        _camera.ShowMask = false;
    }

    private void Signal_CameraAnimationFinished(bool show)
    {
        if (_arrangingScene && !show)
        {
            _arrangingScene = false;
            // prevent place mode recovering
            _player.ResetSkippedPlaceMode();
            _player.EnableInputCheck(true);
            EmitSignal(SignalName.SceneStart);
        }
    }
}
